#include "stdafx.h"
#include "IntroView.h"

#include "GlobalAppData.h"
#include "InputLayouts.h"
#include "HLSLEffect.h"

using namespace intro;

void IntroView::load()
{
	ID3D11Device * device = mcore::GlobalAppData::Instance.Device;

	// vertex buffer
	mgfx::VertexPositionTexture vertices[4];

	vertices[0].Position = XMFLOAT3(-1.0f, -1.0f, 0.5f);
	vertices[1].Position = XMFLOAT3(-1.0f,  1.0f, 0.5f);
	vertices[2].Position = XMFLOAT3( 1.0f, -1.0f, 0.5f);
	vertices[3].Position = XMFLOAT3( 1.0f,  1.0f, 0.5f);

	vertices[0].TextureCoord = XMFLOAT2(-1.0f, -1.0f);
	vertices[1].TextureCoord = XMFLOAT2(-1.0f,  1.0f);
	vertices[2].TextureCoord = XMFLOAT2( 1.0f, -1.0f);
	vertices[3].TextureCoord = XMFLOAT2( 1.0f,  1.0f);

	D3D11_BUFFER_DESC desc;
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(mgfx::VertexPositionTexture) * 4;
	desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;

	D3D11_SUBRESOURCE_DATA data;
	data.pSysMem = vertices;
	data.SysMemPitch = 0;
	data.SysMemSlicePitch = 0;

	HR(device->CreateBuffer(&desc, &data, &mVertexBuffer));
	
	// index buffer
	short indices[6];

	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;

	indices[3] = 1;
	indices[4] = 3;
	indices[5] = 2;

	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(short) * 6;
	desc.BindFlags = D3D11_BIND_INDEX_BUFFER;

	data.pSysMem = indices;

	HR(device->CreateBuffer(&desc, &data, &mIndexBuffer));

	// effect
	mHLSLEffect = mgfx::HLSLEffect::createFromFile("intro.fx");

	mCamera.SetResolution(mcore::GlobalAppData::Instance.ScreenWidth, mcore::GlobalAppData::Instance.ScreenHeight);
	mLightPosition.x = 0.0f;
	mLightPosition.y = 2.0f;
	mLightPosition.z = 1.0f;

	mLoaded = true;
}

void IntroView::unload()
{
	ReleaseCOM(mVertexBuffer);
	ReleaseCOM(mIndexBuffer);

	mLoaded = false;
}

void IntroView::update(float dt)
{
	mTotalTime += dt;
	
	if(GetAsyncKeyState('A') & 0x8000)      mCamera.MoveLeft(20.0f*dt);
    if(GetAsyncKeyState('D') & 0x8000)      mCamera.MoveRight(20.0f*dt);
	if(GetAsyncKeyState('W') & 0x8000)      mCamera.MoveForward(20.0f*dt);
    if(GetAsyncKeyState('S') & 0x8000)      mCamera.MoveBackward(20.0f*dt);

	if(GetAsyncKeyState('I') & 0x8000)      mLightPosition.z += 1.0f * dt;
    if(GetAsyncKeyState('K') & 0x8000)      mLightPosition.z -= 1.0f * dt;
    if(GetAsyncKeyState('J') & 0x8000)		mLightPosition.x += 1.0f * dt;
    if(GetAsyncKeyState('L') & 0x8000)      mLightPosition.x -= 1.0f * dt;

}

void IntroView::draw()
{
	ID3D11DeviceContext * context = mcore::GlobalAppData::Instance.DeviceContext;
	
	uint stride = sizeof(mgfx::VertexPositionTexture);
	uint offset = 0;

	context->IASetInputLayout(mgfx::VertexPositionTexture::InputLayout);
	context->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &offset);
	context->IASetIndexBuffer(mIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	XMFLOAT3 viewDir, right, up;
	mCamera.GetRayGenerationInfo(viewDir, right, up);

	mHLSLEffect->getEffect()->GetVariableByName("gTime")->AsScalar()->SetFloat(mTotalTime);
	mHLSLEffect->getEffect()->GetVariableByName("gCamPos")->AsVector()->SetFloatVector((const float*)&mCamera.GetPosition());
	mHLSLEffect->getEffect()->GetVariableByName("gViewDir")->AsVector()->SetFloatVector((const float*)&viewDir);
	mHLSLEffect->getEffect()->GetVariableByName("gRightToEnd")->AsVector()->SetFloatVector((const float*)&right);
	mHLSLEffect->getEffect()->GetVariableByName("gUpToEnd")->AsVector()->SetFloatVector((const float*)&up);
	mHLSLEffect->getEffect()->GetVariableByName("gLightPos")->AsVector()->SetFloatVector((const float*)&mLightPosition);


	ID3DX11EffectTechnique * effectTech = mHLSLEffect->getEffect()->GetTechniqueByIndex(0);

	D3DX11_TECHNIQUE_DESC techDesc;
	HR(effectTech->GetDesc( &techDesc ));

	for(uint j = 0; j < techDesc.Passes; ++j)
	{
		ID3DX11EffectPass* pass = effectTech->GetPassByIndex(j);
		pass->Apply(0, context);
		context->DrawIndexed(6, 0, 0);
	}

	
}

bool IntroView::onWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch( msg )
	{
	case WM_MOUSEMOVE:
		{
			static bool firstTime = true;
			int mousePosX = LOWORD(lParam);
			int mousePosY = HIWORD(lParam);
			if(firstTime)
			{
				firstTime = false;
			}
			else
			{
				mCamera.RotateX(float(mPrevMousePosY - mousePosY));
				mCamera.RotateY(float(mPrevMousePosX - mousePosX));
			}
			mPrevMousePosX = mousePosX;
			mPrevMousePosY = mousePosY;
			return true;
		}
		break;
	}
	return false;
}